#!/usr/bin/perl

use lib::abs qw( base_lib lib );
use JIP::ToolSet; # load my commonly-used modules in a single import

use DateTime;                            # CPAN modules
use Cwd qw( abs_path );                  #
use File::Copy qw( move );               #
use IPC::Open3 qw( open3 );              #
use English qw( -no_match_vars );        #
use Carp qw( croak );                    #
use File::Spec::Functions qw( catfile ); #
use FindBin qw( $RealBin );              #

use Configurator;                # base lib
use Log;                         #
use Proc::Lock;                  #
use JIP::Utils qw( getLogName ); #

use DB::Schema;                              # searcher custom modules
use Filesystem qw( resolveCrawlerFileName ); #

#-- init settings --------------------------------------------------------------
my $conf = Configurator->new( conf => 'robo_conf.pm' )->getSettings;

#-- init log -------------------------------------------------------------------
our $log = Log->new(
    log_file  => catfile( $conf->crawler->log_dir, getLogName() ),
    log_level => $conf->crawler->log_level,
);

#-- signal handlers ------------------------------------------------------------
require( catfile( $RealBin, 'signal_handlers.pl' ) );

#-- setup lock -----------------------------------------------------------------
$log->Note('setup lock');

my $process = Proc::Lock->new( lock_file => $conf->crawler->lock_file );

$process->lock;

#-- orm handle -----------------------------------------------------------------
my $orm = DB::Schema->connect(
    $conf->sql->dsn,
    $conf->sql->user,
    $conf->sql->pass,
);

$orm->storage->debug( $conf->sql->isDebug );

#-- main -----------------------------------------------------------------------
my $resultSet = $orm->resultset('Ftphosts')->search(
    {
        lastfastscan => {
            '>', DateTime->now( time_zone => $conf->main->time_zone )
                         ->subtract( hours => $conf->main->ageing )
                         ->strftime('%F %T')
        },

        lastindexing => {
            '<', DateTime->now( time_zone => $conf->main->time_zone )
                         ->subtract( hours => $conf->main->ageing )
                         ->strftime('%F %T')
        },
    },
    {
        columns => [ qw( hostip hostid ) ],
    }
);

while ( my $eachHost = $resultSet->next ) {
    $log->Note( 'host '. $eachHost->hostip .' with id '. $eachHost->hostid );

    my $pathToOutputFile = catfile(
        $conf->crawler->scratch_dir,
        resolveCrawlerFileName(
            host_id => $eachHost->hostid,
            host_ip => $eachHost->hostip,
        )
    );

    my $cmdline = join ' ', (
        'perl '.          abs_path('ftp_crawler.pl'),
        '--ip='.          $eachHost->hostip,
        '--user='.        $conf->ftp->user,
        '--pass='.        $conf->ftp->password,
        '--timeout='.     $conf->ftp->timeout,
        '--output_file='. abs_path( $pathToOutputFile ),
    );

    $log->Note( 'starting new crawl. commandline: '. $cmdline );

    my $PID = open3( \*WRITE, \*READ, \*ERROR, $cmdline );

    $SIG{'CHLD'} = sub {
        $log->Note( 'status '. $CHILD_ERROR .' on '. $PID )
            if waitpid( $PID, 0 ) > 0;
    };

    my $isSuccess;

    # read the command output
    while ( <READ> ) {
        if ( /INFO\s+:\s--\sseed\sgenerator\s--/ ) {
            $orm->resultset('Ftphosts')->find( $eachHost->hostid )->update( {
                lastindexing => DateTime->now( time_zone => $conf->main->time_zone )
                                        ->strftime('%F %T')
            } );

            $isSuccess = 1;
        }
    }

    close WRITE;
    close READ;
    close ERROR;

    next unless $isSuccess;

    $log->Note('after the crawl is completed...');

    if ( -f $pathToOutputFile ) {
        if ( -z $pathToOutputFile ) {
            $log->Note( 'file '. $pathToOutputFile .' is empty' );

            unlink $pathToOutputFile
                or croak 'cannot unlink '. $pathToOutputFile .': '. $OS_ERROR;
        }
        else {
            $log->Note('moving file from SCRATCH_DIR to OUTPUT_DIR');

            move( $pathToOutputFile, $conf->crawler->output_dir )
                or croak 'cannot move '. $pathToOutputFile .': '. $OS_ERROR;
        }
    }
    else {
        $log->Error( 'no such output file: '. $pathToOutputFile );
    }
}

#-- finalyze -------------------------------------------------------------------
$log->Note('-- finalyze -----------------------------------------------------');

$log->Note('unset lock...') and $process->unlock;

$log->Note('exiting');

#-- end ------------------------------------------------------------------------
